﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace DrawTools.Tools
{
    /// <summary>
    /// 指针（拾取）
    /// </summary>
    public sealed class PointerDrawTool : DrawingVisual, IDrawTool
    {
        public PointerDrawTool(DrawingCanvas drawingCanvas)
        {
            this.drawingCanvas = drawingCanvas;

            // 准备要处理的事件
            CanTouchDown = true;

            selectedDrawGeometries = new List<DrawGeometryBase>();
        }

        #region 公开方法

        public bool OnKeyDown(Key key)
        {
            if (key == Key.Delete)
            {
                this.DeleteLast();
            }
            return true;
        }

        public bool OnKeyUp(Key key)
        {
            throw new NotImplementedException();
        }

        public bool OnTouchDown(int touchId, Point point)
        {
            if (drawingCanvas.DrawingToolType != DrawingToolType)
            {
                Delete();
                return false;
            }

            TouchId = touchId;

            mode = 0;

            if (VisualParent == null)
            {
                drawingCanvas.AddWorkingDrawTool(this);
                drawingCanvas.Insert(0, this);
            }
            else
            {
                drawingCanvas.MovoToHead(this);

                var visual = drawingCanvas.GetVisual(point);

                if (visual == this || visual is DrawGeometryBase draw && selectedDrawGeometries.Contains(draw))
                {
                    mode = 1;
                    lastPoint = point;
                }
            }

            startPoint = point;

            if (mode == 0)
            {
                selectRect = drawRect = null;

                selectedDrawGeometries.Clear();

                foreach (var draw in drawingCanvas.GetDrawGeometries())
                {
                    if (draw.Select(point))
                    {
                        if (selectRect.HasValue)
                            selectRect = Rect.Union(selectRect.Value, draw.Selected());
                        else
                            selectRect = draw.Selected();

                        selectedDrawGeometries.Add(draw);
                    }
                    else
                        draw.Unselected();
                }

                if (geometry == null)
                {
                    geometry = new PathGeometry();
                    var figure = new PathFigure { StartPoint = point, IsClosed = true, IsFilled = true };
                    geometry.Figures.Add(figure);
                }
                else
                    geometry.Figures[0].StartPoint = point;
            }

            CanTouchMove = true;
            CanTouchUp = true;

            if (TouchId != 0 || !drawingCanvas.CaptureMouse())
                CanTouchLeave = true;

            return true;
        }

        public bool OnTouchEnter(Point point)
        {
            throw new NotImplementedException();
        }

        public bool OnTouchLeave(Point point, bool isLeaved = false)
        {
            return OnTouchUp(point);
        }

        public bool OnTouchMove(Point point)
        {
            if (mode == 0)
            {
                var figure = geometry.Figures[0];

                var topRight = new Point(point.X, startPoint.Y);
                var bottomLeft = new Point(startPoint.X, point.Y);

                if (figure.Segments.Count == 0)
                {
                    var line = new LineSegment(topRight, false);
                    figure.Segments.Add(line);

                    line = new LineSegment(point, false);
                    figure.Segments.Add(line);

                    line = new LineSegment(bottomLeft, false);
                    figure.Segments.Add(line);
                }
                else
                {
                    var line = (LineSegment)figure.Segments[0];
                    line.Point = topRight;

                    line = (LineSegment)figure.Segments[1];
                    line.Point = point;

                    line = (LineSegment)figure.Segments[2];
                    line.Point = bottomLeft;
                }

                selectedDrawGeometries.Clear();

                foreach (var draw in drawingCanvas.GetDrawGeometries())
                {
                    if (draw.Select(geometry))
                    {
                        if (selectRect.HasValue)
                            selectRect = Rect.Union(selectRect.Value, draw.Selected());
                        else
                            selectRect = draw.Selected();

                        selectedDrawGeometries.Add(draw);
                    }
                    else
                        draw.Unselected();
                }

                drawRect = new Rect(startPoint, point);

                var dc = RenderOpen();
                dc.DrawRectangle(null, drawingCanvas.SelectBackgroundPen, drawRect.Value);
                dc.DrawRectangle(null, drawingCanvas.SelectPen, drawRect.Value);
                dc.Close();
            }
            else if (mode == 1)
            {
                // 移动
                var dx = point.X - lastPoint.X;
                var dy = point.Y - lastPoint.Y;

                lastPoint = point;

                foreach (var draw in selectedDrawGeometries)
                {
                    draw.Move(dx, dy);
                }

                var rect = selectRect.Value;
                rect.X += dx;
                rect.Y += dy;
                selectRect = rect;

                var dc = RenderOpen();
                dc.DrawRectangle(Brushes.Transparent, drawingCanvas.SelectBackgroundPen, selectRect.Value);
                dc.DrawRectangle(null, drawingCanvas.SelectPen, selectRect.Value);
                dc.Close();
            }

            return true;
        }

        public bool OnTouchUp(Point point)
        {
            if (mode == 0)
            {
                if (selectedDrawGeometries.Count == 0)
                {
                    Delete();
                    return true;
                }

                if (drawRect.HasValue || selectedDrawGeometries.Count > 1)
                {
                    if (drawRect.HasValue)
                        selectRect = Rect.Union(selectRect.Value, drawRect.Value);

                    var dc = RenderOpen();
                    dc.DrawRectangle(Brushes.Transparent, drawingCanvas.SelectBackgroundPen, selectRect.Value);
                    dc.DrawRectangle(null, drawingCanvas.SelectPen, selectRect.Value);
                    dc.Close();
                }
            }
            else if (mode == 1 && startPoint == lastPoint)
            {
                var visual = drawingCanvas.GetVisual(point);

                if (visual is DrawGeometryBase selectDraw && selectDraw.CanEdit)
                {
                    selectDraw.Edit();

                    foreach (var draw in selectedDrawGeometries)
                    {
                        if (draw != selectDraw)
                            draw.Unselected();
                    }

                    selectedDrawGeometries.Clear();

                    Delete();
                    return true;
                }
            }

            CanTouchMove = false;
            CanTouchUp = false;
            CanTouchLeave = false;

            if (TouchId == 0 && drawingCanvas.IsMouseCaptured)
                drawingCanvas.ReleaseMouseCapture();

            return true;
        }

        #endregion 公开方法

        #region 私有方法

        private void DeleteLast()
        {
            var draw = selectedDrawGeometries.LastOrDefault();
            if (draw == null) return;
            selectedDrawGeometries.Remove(draw);
            drawingCanvas.DeleteVisual(draw);
            drawingCanvas.DeleteWorkingDrawTool(draw);
            if (selectedDrawGeometries.Count == 0)
            {
                Delete();
            }
            drawingCanvas.RefreshTogetherText();
        }

        private void Delete()
        {
            foreach (var draw in selectedDrawGeometries)
            {
                draw.Unselected();
            }

            selectedDrawGeometries.Clear();

            drawingCanvas.DeleteVisual(this);
            drawingCanvas.DeleteWorkingDrawTool(this);

            IsFinish = true;

            CanTouchDown = false;
            CanTouchMove = false;
            CanTouchUp = false;
            CanTouchLeave = false;

            if (TouchId == 0 && drawingCanvas.IsMouseCaptured)
                drawingCanvas.ReleaseMouseCapture();
        }

        #endregion 私有方法

        #region 属性

        public int TouchId { get; private set; }

        public bool CanTouchEnter { get; private set; }

        public bool CanTouchLeave { get; private set; }

        public bool CanTouchDown { get; private set; }

        public bool CanTouchMove { get; private set; }

        public bool CanTouchUp { get; private set; }

        public bool CanKeyDown { get; private set; }

        public bool CanKeyUp { get; private set; }

        public bool IsFinish { get; private set; }

        public DrawToolType DrawingToolType => DrawToolType.Pointer;

        private bool hasDelete = false;

        public bool HasDelete
        { get => hasDelete; set { } }

        public Point StartPoint => new Point();

        public string Text { get; set; }

        public int Index { get; set; }

        public bool ShowIndex { get; set; } = false;
        #endregion 属性

        #region 字段

        private DrawingCanvas drawingCanvas;
        private Point startPoint, lastPoint;
        private List<DrawGeometryBase> selectedDrawGeometries;
        private PathGeometry geometry;
        private Rect? selectRect, drawRect;

        /// <summary>
        /// 0:拾取|1:拖动
        /// </summary>
        private int mode;

        #endregion 字段
    }
}